
#pragma once

#include <AVUIStyleStructures.h>

namespace AVUI {

class HybridDictionary;
typedef ItemStructList< TRefCountedPtr<DependencyObject> > DependencyObjectList;
typedef TArray< TRefCountedPtr<HybridDictionary> > HybridDictionaryArray;

/// <summary>Supports the creation of templates.</summary>
class FrameworkElementFactory : public Object
{
public:
    DECLARE_ELEMENT(FrameworkElementFactory, Object);

#pragma region Public Methods

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkElementFactory" /> class.</summary>
    FrameworkElementFactory();

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkElementFactory" /> class with the specified text to produce.</summary>
    /// <param name="text">The text string to produce.</param>
    FrameworkElementFactory(String* pText);

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkElementFactory" /> class with the specified <see cref="T:System.Type" />.</summary>
    /// <param name="type">The type of instance to create.</param>
    FrameworkElementFactory(const Type* pType);

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkElementFactory" /> class with the specified <see cref="T:System.Type" /> and name.</summary>
    /// <param name="type">The type of instance to create.</param>
    /// <param name="name">The style identifier.</param>
    FrameworkElementFactory(const Type* pType, String* pName);

    /// <summary>Adds an event handler for the given routed event to the instances created by this factory.</summary>
    /// <returns />
    /// <param name="routedEvent">Identifier object for the routed event being handled.</param>
    /// <param name="handler">A reference to the handler implementation.</param>
    void AddHandler(RoutedEvent* pRoutedEvent, Delegate* pHandler) { AddHandler(pRoutedEvent,pHandler,false); }

    /// <summary>Adds an event handler for the given routed event to the instances created by this factory, with the option of having the provided handler be invoked even in cases of routed events that had already been marked as handled by another element along the route.</summary>
    /// <returns />
    /// <param name="routedEvent">Identifier object for the routed event being handled.</param>
    /// <param name="handler">A reference to the handler implementation.</param>
    /// <param name="handledEventsToo">Whether to invoke the handler in cases where the routed event has already been marked as handled in its arguments object. true to invoke the handler even when the routed event is marked handled; otherwise, false. The default is false. Asking to handle already-handled routed events is not common.</param>
    void AddHandler(RoutedEvent* pRoutedEvent, Delegate* pHandler, bool handledEventsToo);

    /// <summary>Adds a child factory to this factory.</summary>
    /// <returns />
    /// <param name="child">The <see cref="T:System.Windows.FrameworkElementFactory" /> object to add as a child.</param>
    void AppendChild(FrameworkElementFactory* pChild);
 
    /// <summary>Removes an event handler from the given routed event. This applies to the instances created by this factory.</summary>
    /// <returns />
    /// <param name="routedEvent">Identifier object for the routed event.</param>
    /// <param name="handler">The handler to remove.</param>
    void RemoveHandler(RoutedEvent* pRoutedEvent, Delegate* pHandler);

    /// <summary>Sets up data binding on a property.</summary>
    /// <param name="dp">Identifies the property where the binding should be established.</param>
    /// <param name="binding">Description of the binding.</param>
    void SetBinding(DependencyProperty* pDP, BindingBase* pBinding) { SetValue(pDP,pBinding); }

    /// <summary>Set up a dynamic resource reference on a child property.</summary>
    /// <returns />
    /// <param name="dp">The property to which the resource is bound.</param>
    /// <param name="name">The name of the resource.</param>
    void SetResourceReference(DependencyProperty* pDP, Object* pName);

    /// <summary>Sets the value of a dependency property.</summary>
    /// <returns />
    /// <param name="dp">The dependency property identifier of the property to set.</param>
    /// <param name="value">The new value.</param>
    void SetValue(DependencyProperty* pDP, Object* pValue);

#pragma endregion Public Methods
 
#pragma region Public Properties

    /// <summary>Gets the first child factory.</summary>
    /// <returns>A <see cref="T:System.Windows.FrameworkElementFactory" /> the first child factory.</returns>
    FrameworkElementFactory* get_FirstChild() { return m_pFirstChild; }

    /// <summary>Gets a value that indicates whether this object is in an immutable state.</summary>
    /// <returns>true if this object is in an immutable state; otherwise, false.</returns>
    bool get_IsSealed() { return m_sealed; }

    /// <summary>Gets or sets the name of a template item.</summary>
    /// <returns>A string that is the template identifier.</returns>
    String* get_Name() { return m_pChildName; }
    void set_Name(String* pValue);

    /// <summary>Gets the next sibling factory.</summary>
    /// <returns>A <see cref="T:System.Windows.FrameworkElementFactory" /> that is the next sibling factory.</returns>
    FrameworkElementFactory* get_NextSibling() { return m_pNextSibling; }

    /// <summary>Gets the parent <see cref="T:System.Windows.FrameworkElementFactory" />.</summary>
    /// <returns>A <see cref="T:System.Windows.FrameworkElementFactory" /> that is the parent factory.</returns>
    FrameworkElementFactory* get_Parent() { return m_pParent; }

    /// <summary>Gets or sets the text string to produce.</summary>
    /// <returns>The text string to produce.</returns>
    String* get_Text() { return m_pText; }
    void set_Text(String* pValue);

    /// <summary>Gets or sets the type of the objects this factory produces.</summary>
    /// <returns>The type of the objects this factory produces.</returns>
    const Type* get_TypeCreated() { return m_pType; }
    void set_TypeCreated(const Type* pValue);

#pragma endregion Public Properties

#pragma region Internal Methods

    static void AddNodeToLogicalTree(DependencyObject* pParent, const Type* pType, bool treeNodeIsFE, FrameworkElement* pTreeNodeFE, FrameworkContentElement* pTreeNodeFCE);
    Object* GetValue(DependencyProperty* pDP);
    TRefCountedPtr<DependencyObject> InstantiateTree(UncommonField<HybridDictionaryArray>* pDataField, DependencyObject* pContainer, DependencyObject* pParent, DependencyObjectList* pAffectedChildren, TRefCountedPtr<DependencyObjectList>* ppNoChildIndexChildren, ItemStructList<ChildPropertyDependent>* pResourceDependents);
    FrameworkObject InstantiateUnoptimizedTree();
    bool IsChildNameValid(String* pChildName);
    static void NewNodeBeginInit(bool treeNodeIsFE, FrameworkElement* pTreeNodeFE, FrameworkContentElement* pTreeNodeFCE);
    void Seal(FrameworkTemplate* pOwnerTemplate);

#pragma endregion Internal Methods

#pragma region Internal Properties

    EventHandlersStore* get_EventHandlersStore() { return m_pEventHandlersStore; }
    void set_EventHandlersStore(EventHandlersStore* pValue) { m_pEventHandlersStore = pValue; }

    FrameworkTemplate* get_FrameworkTemplate() { return m_pFrameworkTemplate; }

    bool get_HasLoadedChangeHandler() { return m_hasLoadedChangeHandler; }
    void set_HasLoadedChangeHandler(bool value) { m_hasLoadedChangeHandler = value; }

#pragma endregion Internal Properties

#pragma region Internal Fields

    int m_childIndex;
    bool m_hasLoadedChangeHandler;
    ItemStructList<PropertyValue> PropertyValues;

#pragma endregion Internal Fields

private:

#pragma region Private Methods

    void AddNodeToParent(DependencyObject* pParent, FrameworkObject childFrameworkObject);
    void ApplyAutoAliasRules();
    TRefCountedPtr<DependencyObject> CreateDependencyObject();
    TRefCountedPtr<String> GenerateChildName();
    bool IsValueDefined(DependencyProperty* pDP);
    static void NewNodeEndInit(bool treeNodeIsFE, FrameworkElement* pTreeNodeFE, FrameworkContentElement* pTreeNodeFCE);
    static void NewNodeStyledParentProperty(DependencyObject* pContainer, bool isContainerAnFE, bool treeNodeIsFE, FrameworkElement* pTreeNodeFE, FrameworkContentElement* pTreeNodeFCE);
    void Seal();
    static void UpdateChildChains(String* pChildID, int childIndex, bool treeNodeIsFE, FrameworkElement* pTreeNodeFE, FrameworkContentElement* pTreeNodeFCE, DependencyObjectList* pAffectedChildren, TRefCountedPtr<DependencyObjectList>* ppNoChildIndexChildren);
    void UpdatePropertyValueList(DependencyProperty* pDP, PropertyValueType::Enum valueType, Object* pValue);

#pragma endregion Private Methods
 
#pragma region Private Fields

    TRefCountedPtr<String> m_pChildName;
    TRefCountedPtr<EventHandlersStore> m_pEventHandlersStore;
    TRefCountedPtr<FrameworkElementFactory> m_pFirstChild;
    TWeakPtr<FrameworkTemplate> m_pFrameworkTemplate;
    TRefCountedPtr<FrameworkElementFactory> m_pLastChild;
    TRefCountedPtr<FrameworkElementFactory> m_pNextSibling;
    TWeakPtr<FrameworkElementFactory> m_pParent;
    bool m_sealed;
    TRefCountedPtr<String> m_pText;
    const Type* m_pType;
    static int AutoGenChildNamePostfix;
    static const WCHAR* AutoGenChildNamePrefix;

#pragma endregion Private Fields


};

}; // namespace AVUI




